home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
001a
/
mskrmsrc.zip
/
MSNPDI.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-10-24
|
12KB
|
402 lines
NAME MSNPDI
; File MSNPDI.ASM
; Packet Driver interface
;
; Copyright (C) 1991, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or
; institution to use, copy, or redistribute this software as long as
; it is not sold for profit and this copyright notice is retained.
;
; Written by Joe R. Doupnik, Utah State University,
; jrd@cc.usu.edu, jrd@usu.Bitnet.
;
; Edit history
; Last edit
; 6 Sept 1991
getintv equ 35h ; DOS get interrupt vector to es:bx
dos equ 21h
pdgetinfo equ 1 ; Packet Driver functions
pd_access equ 2
pd_release equ 3
pd_send equ 4
pd_get_address equ 6
eaddr_len equ 6 ; length of an Ethernet address
ETH_MSS equ 534 ; Correlate with msntcp.h
link struc ; buffer link structure
flag db 0 ; buffer use flag
bufnum db 0 ; buffer write/read sequence number
count dw 0 ; count of items to follow
link ends
linksize equ 4 ; bytes in link structure
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
_DATA SEGMENT
extrn _pktbuf_wrote:word, _pktwnum:byte
pdsignature db 'PKT DRVR' ; signature of a Packet Driver
if_type dw 0 ; interface type
if_class db 0 ; interface class
if_num db 0 ; interface number
notype db 1,2 ; dummy packet type
notypelen equ $-notype ; length of type field for notype
pktbufoff dw 0 ; offset of packet buffer
pendingpkt dw 0 ; offset of packet being confirmed
_DATA ENDS
_TEXT segment
pktdrvr proc near ; Packet Driver interrupt invokation
PKTDRVI:int 60h ; Interrupt number modified by startup code
ret
pktdrvr endp
; pdinit(ðeraddress)
public _pdinit
_pdinit proc near
push bp
mov bp,sp
push es
push si
push di
push ds
mov ax,dgroup
mov ds,ax
mov ax,[bp+4+0] ; get offset of pktbuf
mov pktbufoff,ax ; save locally
mov cx,60h ; interrupt range
pdinit1:mov ah,getintv ; get interrupt vector
mov al,cl ; vector number
int dos
mov si,offset dgroup:pdsignature ; look for signature
push cx
mov cx,length pdsignature ; length of string
mov di,bx
add di,3 ; sig starts 3 bytes from entry point
cld
repe cmpsb ; compare bytes
pop cx
je pdinit3 ; e = found a match
inc cx
cmp cx,80h ; at end of range?
jna pdinit1 ; na = not yet, try another int
stc ; set carry for failure
jmp pdret ; take failure exit
pdinit3:mov byte ptr PKTDRVI+1,cl ; force in new PD interrupt, code mod
; find Ethernet address
mov ah,pdgetinfo ; get Packet Driver information
mov al,0ffh
xor bx,bx ; optional handle
push ds ; this call changes ds and si
push si
call pktdrvr
pop si
pop ds
jc pdret ; c = failure
mov if_type,dx ; save details for access calls
mov if_class,ch
mov if_num,cl
mov ah,pd_access ; access packets
mov al,ch ; Ethernet class
mov bx,dx ; type
mov dl,cl ; interface number
mov cx,notypelen ; type length for notype
mov si,offset dgroup:notype ; TYPE (should match nothing)
mov di,cs
mov es,di
mov di,offset pdrcvr ; ES:DI is our Packet Driver receiver
call pktdrvr
jc pdret ; c = failure
mov bx,ax ; put handle in bx
mov ax,DGROUP ; our data segment
mov es,ax ; segment of Ethernet address buffer
mov di,[bp+4+2] ; get offset of user's buffer
mov cx,eaddr_len ; length of address wanted
mov ah,pd_get_address ; get the ethernet address
push bx ; save handle
call pktdrvr ; get Ethernet address to es:di buf
pop bx
pushf ; save carry flag
mov ah,pd_release ; release this type, bx has handle
call pktdrvr
popf ; recover carry flag
pdret: mov ax,1 ; return C status, 1 for success
jnc pdret1
xor ax,ax ; 0 for failure
pdret1: pop ds ; success
pop di
pop si
pop es
mov sp,bp ; restore stack
pop bp ; recover bp reg
ret
_pdinit endp
; int pdinfo(& int version, & int class, & int pdtype, & int number,
; & int functionality)
public _pdinfo
_pdinfo proc near
push bp
mov bp,sp
mov ah,pdgetinfo ; get Packet Driver information
mov al,0ffh
xor bx,bx ; optional handle
push ds ; this call changes ds and si
push si
call pktdrvr
pop si
pop ds
jc pdinfo1 ; c = failure
push ax ; save al for later use
mov di,[bp+4+0]
mov [di],bx ; return version
mov al,ch ; class
xor ah,ah
mov di,[bp+4+2]
mov [di],ax ; return as an int
mov di,[bp+4+4]
mov [di],dx ; type
mov di,[bp+4+6]
xor ch,ch
mov [di],cx ; interface number, as an int
pop ax ; recover al
mov di,[bp+4+8]
xor ah,ah
mov [di],ax ; functionality, as an int
pdinfo1:mov ax,1 ; C style exit status, 1 = success
jnc pdinfo2 ; nc = success
xor ax,ax ; 0 = failure
pdinfo2:pop bp
ret
_pdinfo endp
; int pdclose(int handle)
; Returns (in AX) 0 if successful, else 1.
public _pdclose
_pdclose proc near
push bp
mov bp,sp
mov bx,[bp+4+0] ; handle
mov ah,pd_release ; release_type
call pktdrvr
mov ax,1 ; assume success
jnc pdclos1 ; nc = success
xor ax,ax ; 0 for failure
pdclos1:pop bp
ret
_pdclose endp
; int pdaccess( char *type, typelen, int *handle)
; Register access for packet TYPE with the Packet Driver
public _pdaccess
_pdaccess proc near
push bp
mov bp,sp
push es
push si
push di
push ds
push es
mov ax,dgroup ; set up data segment addressibility
mov ds,ax
mov al,if_class ; interface class
mov bx,if_type ; interface type (kind)
mov dl,if_num ; interface number
xor dh,dh
mov si,[bp+4+0] ; get offset of packet TYPE buffer
mov cx,[bp+4+2] ; typelen (length of buf contents)
mov di,cs ; ES:DI is our Packet Driver receiver
mov es,di
mov di,offset pdrcvr ; local receiver
mov ah,pd_access ; set access
call pktdrvr
jc pdacc1 ; c = failure
mov si,[bp+4+4] ; offset of handle
mov [si],ax ; return handle
pdacc1: mov ax,1 ; C level status, 1 = success
jnc pdacc2 ; nc = success
xor ax,ax ; 0 = failure
pdacc2: pop es
pop ds
pop di
pop si
pop es
pop bp
ret
_pdaccess endp
; int pkt_send( char *buffer, int length)
; returns 1 on success, 0 on failure
public _pkt_send
_pkt_send proc near
push bp
mov bp,sp
push ds
push si
mov ax,dgroup ; segment of outgoing buffer
mov ds,ax ; will be DS:SI for Packet Driver
mov si,[bp+4+0] ; buffer's offset
mov cx,[bp+4+2] ; buffer's length
mov ah,pd_send ; send packet (buffer = ds:si)
call pktdrvr ; invoke Packet Driver
pktsen1:mov ax,1 ; return C level success (1)
jnc pktsen2 ; nc = success
xor ax,ax ; else C level failure (0)
pktsen2:pop si
pop ds
pop bp
ret
_pkt_send endp
; Our Packet Driver receiver, far called only by the Packet Driver
; packet buffer:linked list
; each link is db flag ; 1 = free, 2 = in use, 4 = allocated
; ; but not in use yet, 0 = end of buf
; ; 8 = read but not freed.
; db _pktwnum ; sequential number of pkt written
; dw count ; length of data field
; db count dup (?) ; the allocated data field
; The head of the chain has a link like all others.
; The end of the chain has a link with flag == 0 and count = -BUFISZE
; to point to the beginning of the buffer (circular).
; Packet buffer garbage collection is done after the PD transfers a
; buffer to the application, and does so by relinking adjacent free
; blocks.
; _pktbuf_wrote is used to remember the link where the last write occurred
; and should be initialized to the tail link to point the next write to
; the beginning of the buffer.
; The Packet Driver calls this first with AX = 0 to obtain a buffer pointer
; in ES:DI from us (0:0 if we refuse the pkt) with CX = packet size, and
; again with AX = 1 to post completion.
; I'm going to turn off interrupts around this code in an attempt to interlock
; access coherently. It may need to be removed later.
pdrcvr proc far ; dummy Packet Driver receiver
or ax,ax ; kind of upcall from PD
jz pdrcvr1 ; z = first, get-a-buffer
; Second upcall, packet has xfered, ds:si set by PD to xfered buffer
pushf ; save interrupt status
cli ; interrupts off
push ds
push si
push bx
push ax ; assume ds:si is wrong
mov ax,dgroup
mov ds,ax ; set ds to our data segment
mov si,pendingpkt ; offset of pkt being confirmed
or si,si ; is it legal (from first upcall)?
jz pdrcvr10 ; z = no, ignore this call
sub si,linksize ; backup to link info
mov byte ptr [si].flag,2 ; flag = 2 for buffer is now ready
mov al,_pktwnum ; write packet number sequencer
mov [si].bufnum,al
inc _pktwnum ; ready it for next write
mov si,pktbufoff ; start of packet buffer
mov al,[si] ; flags byte
; join contiguous free links
pdrcvr8:cmp al,1 ; link is free?
jne pdrcvr9 ; ne = no, look for a free link
mov bx,[si].count ; count of this link
cmp byte ptr [bx+si+linksize],1 ; is next link free?
jne pdrcvr9 ; ne = no, look for free link
mov ax,[bx+si+linksize].count ; count taken from next link
add ax,linksize ; plus the next link's info field
add [si].count,ax ; add it to this count (merge links)
jmp short pdrcvr8 ; reexamine this new longer link
pdrcvr9:add si,[si].count ; look at next link (add count)
add si,linksize ; and link info
mov al,[si].flag ; get link flags
or al,al ; end of list?
jnz pdrcvr8 ; nz = no
mov pendingpkt,0 ; say we are done with second upcall
pdrcvr10:pop ax
pop bx
pop si
pop ds
popf
ret ; yes, quit
pdrcvr1:pushf
cli
push ds ; First upcall, provide buf ptr
push dx
push cx
mov di,dgroup ; get local addressibility
mov ds,di
mov es,di ; packet buffer is in same group
mov di,_pktbuf_wrote ; where last write occurred
or di,di ; NULL?
jz pdrcvr4 ; z = yes, write nothing
mov dl,100 ; retry counter, breaks endless loops
cmp [di].flag,1 ; is this place now free?
je pdrcvr5 ; e = yes, use it
pdrcvr2:add di,[di].count ; point at next link (add count and
add di,linksize ; link overhead)
dec dl ; loop breaker count down
or dl,dl
jz pdrcvr4 ; z = in an endless loop, exit
cmp [di].flag,1 ; is this link free (1)?
je pdrcvr5 ; e = yes, setup storage
cmp di,_pktbuf_wrote ; have we come full circle?
jne pdrcvr2 ; ne = no, keep looking
pdrcvr4:pop cx
pop dx
pop ds ; failure or buffer not available (0)
xor ax,ax ; return what we received in ax
xor di,di ; return ES:DI as null to reject
mov es,di
popf
ret
; this link is free
pdrcvr5:cmp cx,ETH_MSS+40+12 +20 ; LARGEST PACKET WE ACCEPT
ja pdrcvr4 ; a = yes, decline it
add cx,2 ; defense for 8/16 bit xfr mistakes
mov ax,[di].count ; length of available data space
cmp ax,cx ; cx is incoming size, enough space?
jl pdrcvr2 ; l = no, go to next link
mov [di].flag,4 ; mark link flag as being alloc'd (4)
mov dh,_pktwnum ; write pkt sequencer number
mov [di].bufnum,dh ; don't inc this til PD is done
mov _pktbuf_wrote,di ; remember where we wrote last
; leave whole area allocated here
sub ax,cx ; allocated minus incoming packet
cmp ax,60+linksize ; enough for new link and miminal pkt?
jl pdrcvr6 ; l = not enough for next pkt
mov [di].count,cx ; update space really used
push di ; save this link pointer
add di,linksize ; plus current link info
add di,cx ; plus space used = new link point
sub ax,linksize ; available minus new link info
mov [di].flag,1 ; mark new link as free (1)
mov [di].count,ax ; size of new free data area
pop di ; return to current link
pdrcvr6:add di,linksize ; point at data portion for Pkt Drvr
mov pendingpkt,di ; preserve in case host does not
xor ax,ax ; return what we received in ax
pop cx
pop dx
pop ds ; ES:DI is the pkt buffer address
popf
ret
pdrcvr endp
_TEXT ends
end